package com.mytaobao.main.weitao;

import android.content.Context;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.TabLayout;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.baseproject.util.LogUtils;
import com.baseproject.util.MathUtils;
import com.baseproject.util.UIUtils;
import com.mytaobao.R;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import static com.mytaobao.main.weitao.WeiTaoAppBarLayoutBehavior.TabStatus.TAB_STATUS_EXPEND;


/**
 * Created by hp on 2017/4/12.
 */

public class WeiTaoAppBarLayoutBehavior extends AppBarLayout.Behavior{

    boolean mSkipNestedPreScroll;
    private float percent = 0.0f;
    private int minOffset;
    private int maxOffset;
    private int initTabLayoutHeight;

    public WeiTaoAppBarLayoutBehavior() {}

    public WeiTaoAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    int toolbarHeight = UIUtils.dip2px(45);
    int distance;
    float tvMaxScale = (float) 1.3;

    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
        try {
            Field field = WeiTaoAppBarLayoutBehavior.class.getDeclaredField("mSkipNestedPreScroll");
            field.setAccessible(true);
            boolean mSkipNestedPreScroll = (boolean) field.get(this);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        if (dy != 0 && !mSkipNestedPreScroll) {
            int max;
            int min;
            if (dy < 0) { // We're scrolling down
                //getTotalScrollRangeh和getDownNestedPreScrollRange是同一个函数，一个public一个private
                min = -child.getTotalScrollRange();
                max = min + (int)invoke(child, "getDownNestedPreScrollRange", new Class[] {} , new Object[] { });;
            } else { // We're scrolling up
                min = - (int)invoke(child, "getUpNestedPreScrollRange", new Class[] {} , new Object[] { });
                max = 0;
            }
            consumed[1] = computeConsumedOffset(coordinatorLayout, child, dy, min, max);
            LogUtils.d("[onNestedPreScroll] consumed[1] = " + consumed[1]);
        }
    }

    private int computeConsumedOffset(CoordinatorLayout coordinatorLayout, AppBarLayout child, int dy, int min, int max) {
        WeiTaoTabLayout tabLayout = (WeiTaoTabLayout) child.findViewById(R.id.id_tablayout);
        WeiTaoTabCustomView weiTaoTabCustomView = (WeiTaoTabCustomView) tabLayout.getTabAt(0).getCustomView();
        TextView tv = weiTaoTabCustomView.getTextView();
        int consumed = 0;
        int tabLayoutHeight = tabLayout.getHeight();
        LogUtils.d(" tabLayoutHeight = " + tabLayoutHeight);
        if (percent == 0.0f) {
            initTabLayoutHeight = tabLayout.getHeight();
            minOffset = - toolbarHeight;
            maxOffset = (int) (- toolbarHeight - (initTabLayoutHeight - tvMaxScale * tv.getHeight()));
            distance = Math.abs(minOffset - maxOffset);
        }

//        final int curOffset = getTopAndBottomOffset();
        final int curOffset;
        if (initTabLayoutHeight == tabLayoutHeight) {
            curOffset = getTopAndBottomOffset();
        } else {
            curOffset = - toolbarHeight - (initTabLayoutHeight - tabLayoutHeight);
        }

        int newOffset = curOffset - dy;

        LogUtils.d(" minOffset = " + minOffset
        + " maxOffset = " + maxOffset
        + " curOffset = " + curOffset
        + " newOffset = " + newOffset);
        if (minOffset != 0 && curOffset <= minOffset && curOffset >= maxOffset) {
            // If we have some scrolling range, and we're currently within the min and max offsets, calculate a new offset
            newOffset = MathUtils.constrain(newOffset, maxOffset, minOffset);
            if (curOffset != newOffset) {
//                setTopAndBottomOffset(newOffset);
                consumed = curOffset - newOffset;// Update how much dy we have consumed
                applyTransform(tabLayout, newOffset, consumed);
            } else {
                consumed = (int)invoke(this, "scroll", new Class[] { CoordinatorLayout.class, View.class, int.class, int.class, int.class } ,
                        new Object[] { coordinatorLayout, child, dy, - toolbarHeight, max });
            }
        } else {
            consumed = (int)invoke(this, "scroll", new Class[] { CoordinatorLayout.class, View.class, int.class, int.class, int.class } ,
                    new Object[] { coordinatorLayout, child, dy, - toolbarHeight, max });
        }
        return consumed;
    }

    private void ajustLayout(TabLayout tabLayout) {
        int distance = Math.abs(minOffset - maxOffset);
        int childCount = tabLayout.getTabCount();
        for (int i = 0; i < childCount; i++) {
            TabLayout.Tab tab = tabLayout.getTabAt(i);
            WeiTaoTabCustomView tabView = (WeiTaoTabCustomView) tab.getCustomView();
//            tabView.setOffsetTop(distance);
        }
    }

    public enum TabStatus {
        TAB_STATUS_EXPEND,

        TAB_STATUS_SHRINK
    }

    TabStatus tabStatus = TAB_STATUS_EXPEND;

    public TabStatus getTabStatus() {
        return tabStatus;
    }

    private void applyTransform(WeiTaoTabLayout tabLayout, int newOffset, int consumed) {
        int childCount = tabLayout.getTabCount();
        for (int i = 0; i < childCount; i++) {
            TabLayout.Tab tab = tabLayout.getTabAt(i);
            WeiTaoTabCustomView weiTaoTabCustomView = (WeiTaoTabCustomView) tab.getCustomView();
            TextView tv = weiTaoTabCustomView.getTextView();
            ImageView iv = weiTaoTabCustomView.getImageView();

            int distance = Math.abs(minOffset - maxOffset);
            percent = (float) Math.abs(- toolbarHeight - newOffset) / (float) distance;
            float otherPercent = 1 - percent;
            iv.setScaleY(otherPercent);
            iv.setScaleX(otherPercent);

            float curTVScale = MathUtils.constrain((float)((tvMaxScale - 1) * percent + 1) , 1,(float)tvMaxScale);
            tv.setScaleY(curTVScale);
            tv.setScaleX(curTVScale);

            LogUtils.d(" consumed = " + consumed);

            int finalOffset = distance;
            int currentOffest = (int) (distance * percent);
            int offset = - Math.abs(- toolbarHeight - newOffset);
            LogUtils.d("[applyTransform] currentOffest = " + currentOffest);

            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) weiTaoTabCustomView.getLayoutParams();
            params.topMargin = weiTaoTabCustomView.getTop() + (int)(0.3 * - currentOffest);

//            ((View)weiTaoTabCustomView).setTranslationY((float) ((0.5) * offset));
//            weiTaoTabCustomView.offsetTopAndBottom(offset);
//            weiTaoTabCustomView.scrollTo(0, -offset);
//            tv.scrollTo(0, (int) (- Math.abs(- toolbarHeight - newOffset)));
        }

//        if (percent == 1f && tabStatus == TAB_STATUS_EXPEND) {
//            tabLayout.setAppBarOffsetWhenShrink(maxOffset, this);
//            tabStatus = TAB_STATUS_SHRINK;
//        }

        tabLayout.getLayoutParams().height = tabLayout.getHeight() - consumed;
        tabLayout.requestLayout();
    }


    public static Method getMethod(Class clazz, String methodName,
                                   final Class[] classes) throws Exception {
        Method method = null;
        while (method == null && clazz != null) {
            try {
                if(classes.length > 0) {
                    method = clazz.getDeclaredMethod(methodName, classes);
                } else {
                    method = clazz.getDeclaredMethod(methodName);
                }
            } catch (NoSuchMethodException e) {
            }
            clazz = clazz.getSuperclass();
        }
        return method;
    }

    public static Object invoke(final Object obj, final String methodName,
                                final Class[] classes, final Object[] objects) {
        try {
            Method method = getMethod(obj.getClass(), methodName, classes);
            method.setAccessible(true);// 调用private方法的关键一句话
            return method.invoke(obj, objects);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
